package cn.it.config;

import cn.it.anno.*;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public class BeanFactory {

    private static Map<String, Object> map = new HashMap<>();

    static {
        try {
            // 包扫描,把bean注入ioc容器
            Reflections reflections = new Reflections();
            Set<Class<?>> components = reflections.getTypesAnnotatedWith(MyComponent.class);
            Set<Class<?>> services = reflections.getTypesAnnotatedWith(MyService.class);
            Set<Class<?>> repositories = reflections.getTypesAnnotatedWith(MyRepository.class);
            components.addAll(services);
            components.addAll(repositories);
            for (Class<?> aClass : components) {
                Object o = aClass.newInstance();
                // 设置value
                MyComponent component = aClass.getAnnotation(MyComponent.class);
                MyService service = aClass.getAnnotation(MyService.class);
                MyRepository repository = aClass.getAnnotation(MyRepository.class);
                String id = component == null ? (service == null ? repository.value() : service.value()) : component.value();
                // 未设置value，默认类名
                if (Objects.equals("", id)) {
                    id = aClass.getName().substring(aClass.getName().lastIndexOf(".") + 1);
                }
                map.put(id, o);
            }
            // 依赖注入
            Set<Map.Entry<String, Object>> entries = map.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                Object obj = entry.getValue();
                Class<?> objClass = obj.getClass();
                Field[] fields = objClass.getDeclaredFields();
                for (Field field : fields) {
                    // 属性是否有注入注解
                    if (field.isAnnotationPresent(MyAutowired.class)) {
                        // 查找属性set方法注入
                        Method[] methods = objClass.getMethods();
                        String[] split = field.getType().getName().split("\\.");
                        String name =split[split.length-1];
                        for (Method method : methods) {
                            if (method.getName().equals("set" + name)) {
                                method.invoke(obj, map.get(name));
                            }
                        }
                    }
                }
            }
            // 声明式事务,注入代理对象
            for (Map.Entry<String, Object> entry : entries) {
                String id = entry.getKey();
                Object obj = entry.getValue();
                Class<?> objClass = obj.getClass();
                if (objClass.isAnnotationPresent(MyTransactional.class)) {
                    ProxyFactory proxyFactory = (ProxyFactory) map.get("ProxyFactory");
                    Class<?>[] interfaces = objClass.getInterfaces();
                    if (interfaces.length > 0) {
                        obj = proxyFactory.getJdkProxy(obj);
                    } else {
                        obj = proxyFactory.getCglibProxy(obj);
                    }
                    map.put(id,obj);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static Object getBean(String id) {
        return map.get(id);
    }
}
